#include "Connection.h"
#include <sys/syscall.h>

#include <cstring>
#include <iostream>
#include <thread>

#include "EventLoop.h"

using namespace std;

inline auto GetTid() -> decltype(this_thread::get_id()) {
    return this_thread::get_id();
}

Connection::Connection(EventLoop* loop, Socket* cs)
    : loop_(loop), clientSock_(cs) {
    clientCh_ = new Channel(loop->getEpPtr(), cs->GetFd());
    clientCh_->enableReading();
    clientCh_->setET();
    loop_->updateChannel(clientCh_);

    clientCh_->setReadCb(std::bind(&Connection::onMessage, this));
    clientCh_->setWriteCb(std::bind(&Connection::onWrite, this));

    clientCh_->setExitCb(std::bind(&Connection::onExit, this));
    clientCh_->setErrorCb(std::bind(&Connection::onError, this));

    connTime_ = time(nullptr);
    cout << " connTime_ " << connTime_ << endl;

    loop_->insertConn(cs->GetFd(), this);
}

Connection::~Connection() {
    // cout << this_thread::get_id() << " Connection::~Connection()" << endl;
    delete this->clientSock_;
    delete this->clientCh_;
}
void Connection::parseMsg() {
    while (1) {
        // 前四个字节是长度
        int len;
        memcpy(&len, inBuff_.data(), 4);
        if (len + 4 > inBuff_.size()) {
            break;
        }
        string msg(inBuff_.data() + 4, len);
        inBuff_.erease(0, 4 + len);
        messageCb_(shared_from_this(), msg);
    }
}
void Connection::sendMsg(const string& msg) {
    if (isClose_)
        return;
    cout << GetTid() << " Connection::sendMsg" << endl;

    // 数据添加到缓冲区，开启写事件，channel自动调用onWrite
    if (loop_->isIOThread()) {
        // 发送数据，不一定一次性全部发送完毕，当发送数据没有发送完，要关注EPOLLOUT事件
        // 当发送完毕后，及时关闭
        char buff[4]{0};
        int len = msg.size();
        memcpy(buff, &len, 4);
        string m = string(buff, 4) + msg;
        // 数据解包
        // =============================================
        cout << GetTid() << " io  " << endl;
        outBuff_.append(m);
        clientCh_->enableWriting();
    } else {
        // 工作线程提交到IO线程发送
        cout << GetTid() << " worker  " << endl;
        submitSendMsg(msg);
    }
}
void Connection::submitSendMsg(const std::string& msg) {
    loop_->addTask(std::bind(&Connection::sendMsg, this, msg));
}
void Connection::onWrite() {
    // printf("i am %ld thread\n", syscall(SYS_getsid));
    cout << GetTid() << " Connection::onWrite " << endl;
    int wlen =
        ::send(clientSock_->GetFd(), outBuff_.data(), outBuff_.size(), 0);
    if (wlen == 0) {
        // 数据发送完毕，立即关闭写事件
        clientCh_->disableWriting();
    } else if (wlen == -1) {
        onError();
    } else {
        // 数据发送了一部分，剩下的数据继续发送
        outBuff_.erease(0, wlen);
    }
}
void Connection::onMessage() {
    int n = 0;
    while (1) {
        char buff[1024]{0};
        n = read(clientSock_->GetFd(), buff, 1024);
        if (n == -1) {
            if (errno == EINTR) {
                continue;
            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                printf("read over\n");
                parseMsg();
                // 数据读取完毕后，先拆分
                break;
            } else {
                perror("read");
                onError();
                break;
            }
        } else if (n == 0) {
            onExit();
            break;
        } else {
            string msg(buff, n);
            inBuff_.append(msg);
        }
        memset(buff, 0, 1024);
    }
}

void Connection::onError() {
    loop_->closeConn(clientSock_->GetFd());
    errorCb_(shared_from_this());
}
void Connection::onExit() {
    loop_->closeConn(clientSock_->GetFd());
    exitCb_(shared_from_this());
}